from enum import StrEnum
from typing import Dict, Any, List

from tortoise import fields

from base.base_models import BaseModel


class Tag(BaseModel):
    name = fields.CharField(max_length=255, index=True)
    articles: fields.ManyToManyRelation["Article"]

    class Meta:
        table = "tb_blog_tags"


class Category(BaseModel):
    name = fields.CharField(max_length=255, index=True)
    short_name = fields.CharField(max_length=255, index=True)
    parent: fields.ForeignKeyNullableRelation["Category"] = fields.ForeignKeyField(
        "models.Category", related_name="children", null=True
    )
    articles: fields.ReverseRelation["Article"]
    children: fields.ReverseRelation["Category"]

    class Meta:
        table = "tb_blog_categories"

    async def to_dict(self, include_children=True) -> Dict[str, Any]:
        result = {
            "id": str(self.id),
            "name": self.name,
            "short_name": self.short_name,
            "parent_id": str(self.parent_id) if self.parent_id else None,
            "active": bool(self.active),
            "created_at": self.created_at,
            "updated_at": self.updated_at,
        }

        if include_children:
            children = await self.children.all()
            if children:
                result["children"] = [await child.to_dict() for child in children]

        return result

    @classmethod
    async def get_tree(cls, **kwargs) -> List[Dict[str, Any]]:
        root_categories = await cls.filter(
            parent_id__isnull=True, **kwargs
        ).prefetch_related("children")
        return [await category.to_dict() for category in root_categories]


class ArticleStatus(StrEnum):
    DRAFT = "d"
    PUBLISHED = "p"


class Article(BaseModel):
    title = fields.CharField(max_length=255, index=True)
    content = fields.TextField()
    cover = fields.CharField(max_length=255)
    cover_hash = fields.CharField(max_length=255, null=True)
    category: fields.ForeignKeyRelation[Category] = fields.ForeignKeyField(
        "models.Category", related_name="articles"
    )
    tags: fields.ManyToManyRelation[Tag] = fields.ManyToManyField(
        "models.Tag", related_name="articles"
    )
    top = fields.BooleanField()
    status = fields.CharField(max_length=255, default="p")
    views = fields.IntField()
    keywords = fields.CharField(max_length=255, null=True)
    description = fields.CharField(max_length=255, null=True)
    password = fields.CharField(max_length=255, null=True)

    class Meta:
        table = "tb_blog_articles"
        ordering = ["-created_at"]

    async def save(self, *args, **kwargs):
        if not self.description:
            self.description = (
                self.content[:100] if len(self.content) > 100 else self.content
            )
        await super().save(*args, **kwargs)


class Thought(BaseModel):
    content = fields.TextField()

    class Meta:
        table = "tb_blog_thoughts"
